package com.basic.tools.codegen.controller;


import com.basic.tools.codegen.common.Action;
import com.basic.tools.codegen.common.Contant;
import com.basic.tools.codegen.common.Result;
import com.basic.tools.codegen.entity.*;
import com.basic.tools.codegen.entity.domain.GenUtils;
import com.basic.tools.codegen.gen.*;
import com.basic.tools.codegen.mapper.GenTableColumnMapper;
import com.basic.tools.codegen.mapper.GenTableMapper;
import com.basic.tools.codegen.service.DatasourceConfigService;
import com.basic.tools.codegen.service.TemplateConfigService;
import com.basic.tools.codegen.util.CacheUtils;
import com.basic.tools.template.VelocityUtil;
import com.basic.tools.template.entity.TemplateBridge;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.apache.commons.lang.StringUtils;
import org.apache.tomcat.util.http.fileupload.IOUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import java.util.zip.ZipOutputStream;

@RestController
@RequestMapping("gentable")
@Api(tags = "表信息管理")
public class GenTableController {

    @Autowired
    GenTableMapper genTableMapper;

    @Autowired
    GenTableColumnMapper genTableColumnMapper;

    @Autowired
    private DatasourceConfigService datasourceConfigService;

    @Autowired
    HttpServletResponse response;

    @Autowired
    HttpServletRequest request;

    @Autowired
    private TemplateConfigService templateConfigService;


    @ApiOperation(value = "获得数据源列表", notes = "获得数据源列表")
    @PostMapping("/getDataSources")
    public Result getDataSources(@RequestBody RequstEntity requstEntity) {
        List<DatasourceConfig> datasourceConfigs =
                datasourceConfigService.listAll();
        return Action.ok(datasourceConfigs);
    }


    @ApiOperation(value = "修改列信息", notes = "修改列信息")
    @PutMapping("/updateGTC/{id}")
    public Result updateGenTableColumnById(@RequestBody GenTableColumn genTableColumn, @PathVariable("id") Long id) {
        genTableColumn.setColumnId(id);
        int i = genTableColumnMapper.updateGenTableColumn(genTableColumn);
        return Action.ok(i);
    }


    @ApiOperation(value = "修改已导入某张表信息", notes = "修改已导入某张表信息")
    @PutMapping("/{id}")
    public Result updateGenTableById(@RequestBody GenTable genTable, @PathVariable("id") Long id) {
        genTable.setTableId(id);
        int i = genTableMapper.updateGenTable(genTable);
        return Action.ok(i);
    }


    @ApiOperation(value = "查询已导入某张表信息", notes = "查询已导入某张表信息")
    @GetMapping("/{id}")
    public Result selectGenTableById(@PathVariable("id") Long id) {
        GenTable genTable = genTableMapper.selectGenTableById(id);
        return Action.ok(genTable);
    }

    @ApiOperation(value = "删除已导入某张表信息", notes = "删除已导入某张表信息")
    @DeleteMapping("/{id}")
    public Result deleteGenTableById(@PathVariable("id") Long id) {
        GenTable genTableold = genTableMapper.selectGenTableById(id);
        if (genTableold != null) {
            genTableMapper.deleteGenTableByIds(new Long[]{genTableold.getTableId()});
            genTableColumnMapper.deleteGenTableColumnByIds(new Long[]{genTableold.getTableId()});
        }
        return Action.ok(genTableold);
    }

    @ApiOperation(value = "查询未导入表信息", notes = "查询未导入表信息")
    @PostMapping("/table")
    public Result listTableFilter(@RequestBody RequstEntity requstEntity) {
        GenTable genTable = new GenTable();
        Integer sid = requstEntity.getSid();
        genTable.setDatasourceId(sid + "");
        List<GenTable> genTables = genTableMapper.selectGenTableList(genTable);
        List<String> collect = genTables.stream().map(gt -> gt.getTableName()).collect(Collectors.toList());

        HttpSession session = request.getSession();
        List<TableDefinition> tds = CacheUtils.getTableDefinitions(sid, session);
        DatasourceConfig dataSourceConfig = datasourceConfigService.getById(sid);
        GeneratorConfig generatorConfig = GeneratorConfig.build(dataSourceConfig);
        SQLService service = SQLServiceFactory.build(generatorConfig);
        //NeedFresh 是否刷新缓存
        if (tds == null || "1".equals(requstEntity.getNeedFresh())) {
            tds = service.getTableSelector(generatorConfig).getSimpleTableDefinitions();
            session.setAttribute(Contant.TD_SESSION_CACHE + sid, tds);
        }

        List<TableDefinition> re = tdsFilter(tds, requstEntity).filter(td -> !collect.contains(td.getTableName())).collect(Collectors.toList());
        //是否已经导入 1 是
        if ("1".equals(requstEntity.getIsUp())) {
            re = tdsFilter(tds, requstEntity).filter(td -> collect.contains(td.getTableName())).collect(Collectors.toList());
        }

        //如果是已经导入 信息转换将 GenTable 的值转换到 TableDefinition
        if ("1".equals(requstEntity.getIsUp())) {
            for (TableDefinition td : re) {
                List<GenTable> collect1 = genTables.stream().filter(gt -> gt.getTableName().equals(td.getTableName())).collect(Collectors.toList());
                if (collect1.size() > 0) {
                    GenTable genTable1 = collect1.get(0);
                    td.setId(genTable1.getTableId() + "");
                    td.setGid(genTable1.getGid());
                    td.setComment(genTable1.getTableComment());
                }
            }
        }
        return Action.ok(re);
    }

    public Stream<TableDefinition> tdsFilter(List<TableDefinition> tds, RequstEntity requstEntity) {
        Stream<TableDefinition> tdstream = tds.stream().distinct();
        //其他操作
        extAction( tds.stream().distinct().collect(Collectors.toList()));

        String tableComment = requstEntity.getTableComment();
        String tableName = requstEntity.getTableName();
        if (StringUtils.isNotBlank(tableComment)) {
            tdstream = tdstream.filter(td -> td.getComment().indexOf(tableComment) != -1);
        }
        if (StringUtils.isNotBlank(tableName)) {
            tdstream = tdstream.filter(td -> td.getTableName().toLowerCase().indexOf(tableName.toLowerCase()) != -1);
        }
        return tdstream;
    }

    /**
     * 扩展操作
     * @param collect<TableDefinition>
     * @return void
     */
    public void extAction( List<TableDefinition> collect){
        //生成pg序列
//        String restr="drop sequence IF EXISTS PUBLIC.dual_seq;" +
//                "CREATE SEQUENCE  public.dual_seq" +
//                "    INCREMENT 1" +
//                "    START 1" +
//                "    MINVALUE 1" +
//                "    MAXVALUE 9999999999999" +
//                "    CACHE 1;" +
//                "ALTER SEQUENCE public.dual_seq" +
//                "    OWNER TO gpadmin;--tableName: dual";
//        for(TableDefinition td:collect){
//            String tableName=td.getTableName();
//            System.out.println(restr.replaceAll("dual",tableName));
//        }
    }

    @ApiOperation(value = "导入表信息", notes = "导入表信息")
    @PostMapping("/tableImport")
    public Result tableImport(@RequestBody RequestTableImport requestTableImport
    ) {
        String tableName = requestTableImport.getTableName();
        String comment = requestTableImport.getComment();
        Integer sid = requestTableImport.getSid();
        //拿取表信息
        TableDefinition tableDefinition = new TableDefinition();
        tableDefinition.setTableName(tableName);
        tableDefinition.setComment(comment);

        DatasourceConfig dataSourceConfig = datasourceConfigService.getById(sid);

        GeneratorConfig generatorConfig = GeneratorConfig.build(dataSourceConfig);
        SQLService sQLService = SQLServiceFactory.build(generatorConfig);
        List<ColumnDefinition> columnDefinitions1 = sQLService.getTableSelector(generatorConfig).getColumnSelector().getColumnDefinitions(tableName);

        List<ColumnDefinition> listj = new ArrayList<>();
        for (ColumnDefinition cd : columnDefinitions1) {
            JavaColumnDefinition jcd = new JavaColumnDefinition();
            BeanUtils.copyProperties(cd, jcd);
            listj.add(jcd);
        }
        //表信息导入数据库中
        tableDefinition.setColumnDefinitions(listj);
        GenTable genTable = GenUtils.tableD2tableG(tableDefinition, sid + "");
        GenTable genTableold = genTableMapper.selectGenTableByName(tableName, sid + "");
        if (genTableold != null) {
            genTableMapper.deleteGenTableByIds(new Long[]{genTableold.getTableId()});
            genTableColumnMapper.deleteGenTableColumnByIds(new Long[]{genTableold.getTableId()});
        }
        genTableMapper.insertGenTable(genTable);
        genTable.getColumns().forEach(gtc -> genTableColumnMapper.insertGenTableColumn(gtc.setTableId(genTable.getTableId())));

        return Action.ok(genTable);
    }


    @ApiOperation(value = "修改已导入某张表信息", notes = "修改已导入某张表信息")
    @PostMapping("/updateGen")
    public Result updateGenTableById(@RequestBody GenTable genTable) {
        genTableMapper.updateGenTable(genTable);
        genTableColumnMapper.deleteGenTableColumnByIds(new Long[]{genTable.getTableId()});
        genTable.getColumns().forEach(gtc -> genTableColumnMapper.insertGenTableColumn(gtc.setTableId(genTable.getTableId())));
        return Action.ok(genTable);
    }


    @ApiOperation(value = "生成某张表代码", notes = "生成某张表代码")
    @GetMapping("/codeGen/{tableId}")
    public void codeGenTableId(HttpServletResponse response, @PathVariable Long tableId) throws IOException {
        GenTable genTable = genTableMapper.selectGenTableById(tableId);
        List<TemplateBridge> listt = GenUtils.getTemplateBridges(genTable);
        byte[] redata = VelocityUtil.generatorCode(listt);
        VelocityUtil.genCodeResponse(response, redata);
    }

    @ApiOperation(value = "生成多张表代码", notes = "生成多张表代码")
    @PostMapping("/codeGenTableByIds")//Request<String> request
    public void codeGenTableByIds(HttpServletResponse response, @RequestParam("ids") String[] request) throws IOException {
        List<TemplateBridge> listt = new ArrayList<>();
        String[] ids = request;//request.getIds();
        for (String id : ids) {
            GenTable genTable = genTableMapper.selectGenTableById(Long.parseLong(id));
            listt.addAll(GenUtils.getTemplateBridges(genTable));
        }
        byte[] redata = VelocityUtil.generatorCode(listt);
        VelocityUtil.genCodeResponse(response, redata);
    }


    @ApiOperation(value = "生成某张表-在线模板-代码", notes = "生成某张表-在线模板-代码")
    @GetMapping("/codeGenByOnlie/{tableId}")
    public void codeGenByOnlie(HttpServletResponse response, @PathVariable Long tableId) throws IOException {
        GenTable genTable = genTableMapper.selectGenTableById(tableId);

        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
        ZipOutputStream zip = new ZipOutputStream(outputStream);

        List<TemplateConfig> templateConfigs = templateConfigService.listByGroupId(genTable.getGid());
        GenUtils.generTableByOnline(templateConfigs, genTable, zip,templateConfigService);

        org.apache.tomcat.util.http.fileupload.IOUtils.closeQuietly(zip);
        byte[] redata = outputStream.toByteArray();
        VelocityUtil.genCodeResponse(response, redata);
    }


    @ApiOperation(value = "生成多张表-在线模板-代码", notes = "生成多张表-在线模板-代码")
    @PostMapping("/codeGenByOnlies")
    public void codeGenByOnlies(HttpServletResponse response, @RequestParam("ids") String[] request) throws IOException {

        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
        ZipOutputStream zip = new ZipOutputStream(outputStream);

        for (String tableId : request) {
            GenTable genTable = genTableMapper.selectGenTableById(Long.parseLong(tableId));
            List<TemplateConfig> templateConfigs = templateConfigService.listByGroupId(genTable.getGid());
            GenUtils.generTableByOnline(templateConfigs, genTable, zip,templateConfigService);
        }

        IOUtils.closeQuietly(zip);
        byte[] redata = outputStream.toByteArray();
        VelocityUtil.genCodeResponse(response, redata);
    }


}
